#include <stdio.h>

#include "plf.h"
#include "driver_system.h"
#include "co_printf.h"

#include "driver_pmu.h"
#include "driver_exti.h"
#include "driver_gpio.h"

struct exti_t *exti_regs = (struct exti_t *)EXTI_BASE;
uint32_t *ext_int0en_reg = (uint32_t *)EXT_INT0_EN;

/*********************************************************************
 * @fn     exti_enable
 *
 * @brief   enable gpio exter interrupt 
 *
 * @param   gpio_pin    - @ref driver_system  ex:GPIO_PA0
 *          
 * @return  None.
 */
void exti_enable(uint32_t gpio_pin)
{
    exti_regs->ext_int0_control |= gpio_pin;
}

/*********************************************************************
 * @fn     exti_disable
 *
 * @brief   unenable gpio exter interrupt 
 *
 *@param   gpio_pin    - @ref driver_system  ex:GPIO_PA0
 *
 * @return  None.
 */
void exti_disable(uint32_t gpio_pin)
{
   exti_regs->ext_int0_control &= (~gpio_pin);
}

/*********************************************************************
 * @fn     exti_get_status
 *
 * @brief   return exter interrupt status
 *
 * @param   void
 * @return  ext_int_status.
 */
uint32_t exti_get_status(void)
{
    return exti_regs->ext_int0_status ;
}

/*********************************************************************
 * @fn     exti_clear
 *
 * @brief   clear gpio exter interrupt 
 *
 * @param   bit        - @ref driver_system  ex:GPIO_PA0.
 *
 * @return  None.
 */
void exti_clear(uint32_t bit)
{
    exti_regs->ext_int0_status  = bit;
}

/*********************************************************************
 * @fn     exti_set_type
 *
 * @brief   set gpio exter interrup trigger type
 *
 * @param   gpio_pin    - @ref driver_system   
 *          type        - @ref ext_int_type_t
 *
 * @return  None.
 */
void exti_set_type(enum exti_gpio_pin gpio_pin, enum exti_type_t type)
{
    uint8_t offset, index;
    uint32_t value;
    index = gpio_pin /16;
    offset = (gpio_pin %16) << 1;

    value = exti_regs->ext_int_type[index];
    value &= (~(EXT_INT_TYPE_MSK<<offset));
    value |= (type << offset);
    exti_regs->ext_int_type[index] = value;
}

/*********************************************************************
 * @fn     exti_set_control
 *
 * @brief   set gpio extern fractional frequency and  simpling frequency
 *
 * @param   gpio_pin    - @ref exti_gpio_pin.
 *          clk         - set self frequency 
 *          counter     - simoling frequency
 *
 * @return  None.
 */
void exti_set_control(enum exti_gpio_pin gpio_pin, uint32_t clk, uint8_t counter)
{
    uint32_t pclk;
    system_regs->misc.gpio_clk_div = system_get_pclk_config();
    pclk = 1000000;
    exti_regs->ext_int_cnt[gpio_pin] =((pclk/clk-1)<<8) | (counter-1) ;
}

/*********************************************************************
 * @fn     exti_isr
 *
 * @brief   rewrite interrupt service function
 *
 * @param   void
 *
 * @return  None.
 */
void exti_isr(void)
{
    uint32_t status;
    status = exti_get_status();
    exti_clear(status);
    co_printf("enter the interrupt !!!\r\n");
}

